package com.shiyi.shiyiaicodefather.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import com.shiyi.shiyiaicodefather.exception.BusinessException;
import com.shiyi.shiyiaicodefather.exception.ErrorCode;
import com.shiyi.shiyiaicodefather.exception.ThrowUtils;
import com.shiyi.shiyiaicodefather.service.ProjectDownloadService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileFilter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Set;

@Slf4j
@Service
public class ProjectDownloadServiceImpl implements ProjectDownloadService {

  /**
   * 需要过滤的文件和目录名称
   */
  private static final Set<String> IGNORED_NAMES = Set.of(
    "node_modules",
    ".git",
    "dist",
    "build",
    ".DS_Store",
    ".env",
    "target",
    ".mvn",
    ".idea",
    ".vscode"
  );

  /**
   * 需要过滤的文件扩展名
   */
  private static final Set<String> IGNORED_EXTENSIONS = Set.of(
    ".log",
    ".tmp",
    ".cache"
  );

  /**
   * 检查路径是否允许包含在压缩包中
   *
   * @param projectRoot 项目根目录
   * @param fullPath    完整路径
   * @return 是否允许
   */
  private boolean isPathAllowed(Path projectRoot, Path fullPath) {
    // 获取相对路径
    Path relativePath = projectRoot.relativize(fullPath);
    // 检查路径中的每一部分
    for (Path part : relativePath) {
      String partName = part.toString();
      // 检查是否在忽略名称列表中
      if (IGNORED_NAMES.contains(partName)) {
        return false;
      }
      // 检查文件扩展名
      if (IGNORED_EXTENSIONS.stream().anyMatch(partName::endsWith)) {
        return false;
      }
    }
    return true;
  }

  @Override
  public void downloadProjectAsZip(String projectPath, String downloadFileName, HttpServletResponse response) {
    // 基础校验
    ThrowUtils.throwIf(StrUtil.isBlank(projectPath), ErrorCode.PARAMS_ERROR, "项目路径不能为空");
    ThrowUtils.throwIf(StrUtil.isBlank(downloadFileName), ErrorCode.PARAMS_ERROR, "下载文件名不能为空");
    File projectDir = new File(projectPath);
    ThrowUtils.throwIf(!projectDir.exists(), ErrorCode.NOT_FOUND_ERROR, "项目目录不存在");
    ThrowUtils.throwIf(!projectDir.isDirectory(), ErrorCode.PARAMS_ERROR, "指定路径不是目录");
    log.info("开始打包下载项目: {} -> {}.zip", projectPath, downloadFileName);
    // 设置 HTTP 响应头
    response.setStatus(HttpServletResponse.SC_OK);
    response.setContentType("application/zip");
    response.addHeader("Content-Disposition",
      String.format("attachment; filename=\"%s.zip\"", downloadFileName));
    // 定义文件过滤器
    FileFilter filter = file -> isPathAllowed(projectDir.toPath(), file.toPath());
    try {
      // 使用 Hutool 的 ZipUtil 直接将过滤后的目录压缩到响应输出流
      ZipUtil.zip(response.getOutputStream(), StandardCharsets.UTF_8, false, filter, projectDir);
      log.info("项目打包下载完成: {}", downloadFileName);
    } catch (Exception e) {
      log.error("项目打包下载异常", e);
      throw new BusinessException(ErrorCode.SYSTEM_ERROR, "项目打包下载失败");
    }
  }

}

